﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spectrum
{
    /// <summary>
    /// 单质点响应集合
    /// </summary>
    public class ResponseSet
    {
        #region Variables

        /// <summary>
        /// 响应时程
        /// </summary>
        private List<ResponseParam> responseSet { set; get; }

        /// <summary>
        /// 加速度激励时程
        /// </summary>
        private List<AccelParam> accelSet { set; get; }

        /// <summary>
        /// 周期
        /// </summary>
        private float Period { set; get; }

        /// <summary>
        /// 阻尼比
        /// </summary>
        private float DampR { set; get; }

        #endregion

        #region Properties

        /// <summary>
        /// 获得某时刻的响应
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public ResponseParam this[int index]
        {
            get
            {
                return this.responseSet[index];
            }
        }

        /// <summary>
        /// 获得位移响应最大值
        /// </summary>
        public float Umax
        {
            get
            {
                //初始化
                double max = new double();
                //遍历时程响应
                this.responseSet.ForEach(response =>
                max = Math.Max(max, Math.Abs(response.U)));
                //返回最大响应
                return (float)max;
            }
        }

        /// <summary>
        /// 影响系数最大值
        /// </summary>
        private float Afamax
        {
            get
            {
                //初始化
                double max = new double();
                //遍历时程响应
                this.responseSet.ForEach(response =>
                max = Math.Max(max, Math.Abs(response.A)));
                //返回最大响应
                return (float)max;
            }
        }

        /// <summary>
        /// 速度响应最大值
        /// </summary>
        private float Vmax
        {
            get
            {
                //初始化
                double max = new double();
                //遍历时程响应
                this.responseSet.ForEach(response =>
                max = Math.Max(max, Math.Abs(response.V)));
                //返回最大响应
                return (float)max;
            }
        }

        /// <summary>
        /// 响应点数目
        /// </summary>
        private int Count
        {
            get
            {
                return this.responseSet.Count;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// SRSS组合
        /// </summary>
        /// <param name="yResponseSet"></param>
        /// <returns></returns>
        public ResponseSet GetSRSSResponse(ResponseSet yResponseSet)
        {
            //响应点数目
            int count = Math.Min(this.Count, yResponseSet.Count);
            //初始化
            var responseSet = new ResponseSet(count,this.Period, this.DampR);
            //添加相应
            for(int i = 0; i < count; i++)
                responseSet.Add(this[i], yResponseSet[i]);
            //返回相应
            return responseSet;
        }

        /// <summary>
        /// 添加SRSS分析结果
        /// </summary>
        /// <param name="paramX"></param>
        /// <param name="paramY"></param>
        private void Add(ResponseParam paramX, ResponseParam paramY)
        {
            this.responseSet.Add(new ResponseParam(paramX, paramY));
        }

        /// <summary>
        /// NewMark积分
        /// </summary>
        /// <param name="DampR"> 阻尼比 </param>
        /// <param name="wn"> 无阻尼圆频率 </param>
        /// <param name="wd"> 带阻尼圆频率 </param>
        /// <param name="pDict">  激励(时间，加速度) </param>
        /// <param name="beta"> Newmark参数 </param>
        /// <param name="gamma"> Newmark参数 </param>
        /// <param name="dt"> 积分步长 </param>
        /// <returns></returns>
        private void Newmark(List<float> paramList)
        {
            //初始化
            this.responseSet = new List<ResponseParam>(this.accelSet.Count);
            //基本参数
            float wn = SpectrumMethod.Getwn(this.Period);
            float wd = SpectrumMethod.Getwd(this.Period, this.DampR);
            float M = 1;
            float K = M * (float)Math.Pow(wn, 2);
            float C = 2 * M * wn * this.DampR;
            //等效刚度
            float KK = K + paramList[0] * M + paramList[1] * C;
            //初始状态
            float ust = 0; float vst = 0; float ast = 0;
            //初始化参数
            this.accelSet.ForEach(accelParam =>
            {
                var PP = accelParam.Accel * M + M * (paramList[0] * ust + paramList[2] * vst + paramList[3] * ast) +
                C * (paramList[1] * ust + paramList[4] * vst + paramList[5] * ast);
                var u = PP / KK;
                var preu = ust; var prev = vst; var prea = ast;
                ust = u;
                ast = paramList[0] * (u - preu) - paramList[2] * prev - paramList[3] * prea;
                vst = vst + paramList[6] * prea + paramList[7] * ast;
                this.responseSet.Add(new ResponseParam(accelParam.Time, ust, ast, vst));
            });
        }

        /// <summary>
        /// 获得影响系数最大值
        /// </summary>
        /// <param name="isPseudo"></param>
        /// <returns></returns>
        public float GetAfaMax(bool isPseudo)
        {
            return isPseudo ? this.Umax * (float)Math.Pow(SpectrumMethod.Getwn(this.Period), 2) : this.Afamax;
        }

        /// <summary>
        /// 速度响应最大值
        /// </summary>
        /// <param name="isPseudo"></param>
        /// <returns></returns>
        public float GetVelocityMax(bool isPseudo)
        {
            return isPseudo ? this.Umax * SpectrumMethod.Getwn(this.Period) : this.Vmax;
        }

        #endregion

        #region Constructors

        /// <summary>
        /// 构造函数
        /// </summary>
        public ResponseSet()
        {
            this.responseSet = new List<ResponseParam>();
            this.accelSet = new List<AccelParam>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public ResponseSet(int count, float period, float dampR)
        {
            this.responseSet = new List<ResponseParam>(count);
            this.accelSet = new List<AccelParam>();
            this.Period = period;
            this.DampR = dampR;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="accels"></param>
        public ResponseSet(List<AccelParam> accels, List<float> paramList, float period, float dampR)
        {
            //获得时程响应
            this.accelSet = accels;
            //获得周期
            this.Period = period;
            this.DampR = dampR;
            //计算时程响应
            this.Newmark(paramList);
        }

        #endregion
    }

    /// <summary>
    /// 单质点响应参数
    /// </summary>
    public class ResponseParam
    {
        /// <summary>
        /// 时刻
        /// </summary>
        public float Time { set; get; }

        /// <summary>
        /// 响应
        /// </summary>
        public float U { set; get; }

        /// <summary>
        /// 响应
        /// </summary>
        public float A { set; get; }

        /// <summary>
        /// 响应
        /// </summary>
        public float V { set; get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public ResponseParam()
        {

        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="time"></param>
        /// <param name="response"></param>
        public ResponseParam(float time, float u, float a, float v)
        {
            this.Time = time;
            this.U = u;
            this.A = a;
            this.V = v;
        }

        /// <summary>
        /// 平方和开方
        /// </summary>
        /// <param name="paramX"></param>
        /// <param name="paramY"></param>
        public ResponseParam(ResponseParam paramX, ResponseParam paramY)
        {
            this.Time = paramX.Time;
            this.U = (float)Math.Sqrt(Math.Pow(paramX.U, 2) + Math.Pow(paramY.U, 2));
            this.A = (float)Math.Sqrt(Math.Pow(paramX.A, 2) + Math.Pow(paramY.A, 2));
            this.V = (float)Math.Sqrt(Math.Pow(paramX.V, 2) + Math.Pow(paramY.V, 2));
        }
    }
}
